{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# python面向对象\n",
    "* python是面向对象语言的集大成者这一点毋庸置疑,处处皆对象,这也就使得python语言能够用最简短的代码来做复杂的事情,程序的可读性也很高.因此用面向对象的程序思想来编写   python程序是很有必要的.\n",
    "* 类是有属性和方法构成的,对象实例化也就意味着给类注入了灵魂即(数据),面向对象程序设计有了思想之后主要需要解决的就是如何去操作数据与如何去使用方法来操作数据,以及如何去操作类中的数据方法和对象中的数据方法\n",
    "* 在操作数据的前提就是如何去访问数据,既然这样为了确保数据的完整性以及封装性也就有了属性和方法的访问权限设置\n",
    "* 当一个类创建了之后或者是类实例化成为对象之后如何在保留原有类或者是对象的基础上增加其他的属性或者是方法嘞？对于这个问题python也解决了也就产生绑定和继承的扩展语法\n",
    "* 总而言之面向对象的思想是核心,语法只是形式所有的语法都是为了更好的操作数据以及更好的使用方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "1.类的定义\n",
    "\n",
    "class name(object):\n",
    "    '''注释'''\n",
    "    sentence\n",
    "    .....\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "clas_a： ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']\n",
      "clas_b: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']\n"
     ]
    }
   ],
   "source": [
    "'''\n",
    "c以下三个类的定义方式是等同的,所有类都默认继承了一个object类这是所有类的父类,\n",
    "这个父类有很多的类方法可供子类使用\n",
    "'''\n",
    "class clas_a():\n",
    "    pass\n",
    "\n",
    "class clas_b(object):\n",
    "    pass\n",
    "\n",
    "class clas_c:\n",
    "    pass\n",
    "print('clas_a：',dir(clas_a))\n",
    "print('clas_b:',dir(clas_b))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "clas_a\n",
      "{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'clas_a' objects>, '__weakref__': <attribute '__weakref__' of 'clas_a' objects>, '__doc__': None}\n",
      "clas_b\n",
      "{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'clas_b' objects>, '__weakref__': <attribute '__weakref__' of 'clas_b' objects>, '__doc__': None}\n"
     ]
    }
   ],
   "source": [
    "# 通过类字典来查看类中的方法和属性\n",
    "print('clas_a')\n",
    "pirint(clas_a.__dict__)\n",
    "print('clas_b')\n",
    "tprint(clas_b.__dict__)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 可以看到不管是用dir查看属性方法还是用__dict__方法查看属性和方法,对于两个空类来说都是一样的其属性和方法就是继承至共同父类object的属性和方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* python中为了操作数据方便根据类没有实例化与实例化对象其变量和方法的使用方式也分为两种\n",
    "```python\n",
    "|-1.staticvariable,classvariable\n",
    "|-2.staticmethod,classmethod\n",
    "staticvariable 和 staticmethod是只能通过实例化对象访问和使用\n",
    "而classmethod只能通过类调用不能通过对象调用,classvariable即能通过类调用又能通过对象访问\n",
    "static和class类型可以通过装饰器@staticmethod和@classmethod转换\n",
    "具体形式见下例:\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "通过对象调用静态变量\n",
      "6\n",
      "通过类名使用访问静态变量\n",
      "6\n",
      "通过类名调用静态方法\n",
      "我是静态方法\n",
      "通过对象名调用静态方法\n"
     ]
    },
    {
     "ename": "TypeError",
     "evalue": "static_method() takes 0 positional arguments but 1 was given",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-19-6b6de63ca747>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     11\u001b[0m \u001b[0mclass_method_vari\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstatic_method\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     12\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"通过对象名调用静态方法\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 13\u001b[1;33m \u001b[0mobj_a\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstatic_method\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m   \u001b[1;31m#调用不了TypeError出错\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m: static_method() takes 0 positional arguments but 1 was given"
     ]
    }
   ],
   "source": [
    "class class_method_vari(object):\n",
    "    static = 6\n",
    "    def static_method():\n",
    "        print('我是静态方法')\n",
    "obj_a = class_method_vari()\n",
    "print('通过对象调用静态变量')\n",
    "print(obj_a.static)\n",
    "print('通过类名使用访问静态变量')\n",
    "print(class_method_vari.static)\n",
    "print('通过类名调用静态方法')\n",
    "class_method_vari.static_method()\n",
    "print(\"通过对象名调用静态方法\")\n",
    "obj_a.static_method()   #调用不了TypeError出错"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "对于类变量和类函数来说当程序执行的时候会加载进去类变量会分配储存空间,\n",
    "这时候类变量就相当于是全局变量,在任何地方都可以使用,这个是不依赖与对\n",
    "象所存在的只不过在使用的时候要用加上了类名的前缀而类函数则会加载当通\n",
    "过类名调用的时候才会给其数据分配存储空间,类函数也相当于是全局函数只\n",
    "不过在使用的时候也加上前缀罢了\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "对象访问self变量a,b\n",
      "1 2\n",
      "对象访问self函数\n",
      "3\n"
     ]
    },
    {
     "ename": "NameError",
     "evalue": "name 'tactic_cls' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-44-4b734826b5e0>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     15\u001b[0m \u001b[1;31m#下面两种方式都是错误的\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     16\u001b[0m \u001b[1;31m#print(tactic_cls.a,tactic_cls.b)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 17\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtactic_cls\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msumcount\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m: name 'tactic_cls' is not defined"
     ]
    }
   ],
   "source": [
    "# 函数加了self或者变量加了self就变成了静态变量和静态函数只能由对象调用\n",
    "class tatic_cls:\n",
    "    #self.c = 3               #在方法外面定义静态变量都是错误的\n",
    "    def __init__(self,a,b):\n",
    "        self.a = a\n",
    "        self.b = b\n",
    "    def sumcount(self):\n",
    "        return self.a + self.b\n",
    "    #self.c = 2                 #在方法外面定义静态变量都是错误的\n",
    "obj_stctic = tatic_cls(1,2)\n",
    "print('对象访问self变量a,b')\n",
    "print(obj_stctic.a,obj_stctic.b)\n",
    "print('对象访问self函数')\n",
    "print(obj_stctic.sumcount())\n",
    "#下面两种方式都是错误的\n",
    "#print(tactic_cls.a,tactic_cls.b)\n",
    "#print(tactic_cls.sumcount())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "|-self 的意义:\n",
    "    self是代表一个对象的应用,一个类在理论上来说可以创建无数个对象,但是类中有类属性和对象属性,而类属性是这个类\n",
    "    的实例化对象所共有的,但是通过这个类创建的无数个对象不同的对象可能就有不同的对象属性那么在使用属性的时候如何\n",
    "    去区分不同对象的不同属性嘞？这就要靠这个self参数,self参数是对象属性对象方法的标志,依赖self的属性和方法都是\n",
    "    依赖对象的存在,同一个类不同的多态对象也就产生了不同的self,也就是说self是与对象一一对应的,不同的self传递给\n",
    "    类就可以使用不同的属性,self的意义也就在于为了让类区分不同的对象属性.\n",
    "|-静态属性和方法说明:\n",
    "    静态属性和方法就是使用了前缀self的变量和使用了参数self的方法,self是依赖与对象的因此静态变量和静态方法即对象成员变量\n",
    "    和成员方法也是依赖于对象的存在,在对象实例化的时候才会分配内存储存数据,且与对象同生共死\n",
    "|-__init__方法的说明:\n",
    "    __init__方法也叫作构造方法,其作用是用来给self变量赋值的,可以自己手动构造self方法当定义类的时候没有定义self方法\n",
    "    的时候解释器会自动给类加上一个空的__init__方法,因此创建类的时候不定义__init__方法也是行得通的,__init__方法当类\n",
    "    实例化成为对象的时候会自动调用,因为__init__方法的调用是依赖与对象的所以其参数必须要带上self.\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "通过对象调用成员函数\n",
      "3\n",
      "给成员函数传递一个对象后用过类名直接调用\n",
      "3\n"
     ]
    }
   ],
   "source": [
    "class cls_a:\n",
    "    def __init__(self,a,b):\n",
    "        self.a = a\n",
    "        self.b = b\n",
    "    def function(self):\n",
    "        return self.a + self.b\n",
    "obj_a = cls_a(1,2)    #在实例化对象的时候传递参数给self.a,self.b\n",
    "print('通过对象调用成员函数')\n",
    "print(obj_a.function())\n",
    "#print(cls_a.function())   #这个是错误的因为静态变量和方法是依赖于对象的没有对象类必然不能调用\n",
    "print('给成员函数传递一个对象后用过类名直接调用') \n",
    "print(cls_a.function(obj_a)) #这个是正确的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "通过对象调用原类方法\n",
      "8\n",
      "通过类使用通过静态装饰了的类方法\n",
      "8\n",
      "通过类名调用类装饰器装饰了的静态方法\n",
      "6\n",
      "通过对象调用类装饰器装饰了的静态方法\n",
      "6\n"
     ]
    }
   ],
   "source": [
    "#静态方法与动态方法用装饰器相互转化\n",
    "class cls_b:\n",
    "    def __init__(self,a,b):\n",
    "        self.a = a\n",
    "        self.b = b\n",
    "    '''\n",
    "    @staticmethod\n",
    "    def class_fun1():\n",
    "        return self.a*self.b\n",
    "    注意这种方式是错误的,因为类方法是全局函数其内不能使用成员变量\n",
    "    最关键的是他没有self参数不解释器不能够给他传递对象,而self变量\n",
    "    即成员变量的使用是依赖于对象的\n",
    "    '''\n",
    "    @staticmethod     #将类方法变换成静态方法\n",
    "    def class_fun(p1:int,p2:int)->int:\n",
    "        return p1*p2\n",
    "    '''\n",
    "    @classmethod      #将静态方法变换成类方法\n",
    "    def static_fun(self):\n",
    "        return self.a+self.b\n",
    "    这种方式也是错误的这个函数虽然有self参数但是装饰之后解释器会\n",
    "    不断的给self传递类本身,因此也不能使用成员变量\n",
    "    '''\n",
    "    @classmethod\n",
    "    def static_fun(self,a,b):\n",
    "        return a+b\n",
    "obj_a = cls_b(2,4)\n",
    "print('通过对象调用原类方法')\n",
    "print(obj_a.class_fun(2,4))\n",
    "print('通过类使用通过静态装饰了的类方法')\n",
    "print(cls_b.class_fun(2,4))\n",
    "#print(obj_a.class_fun1(obj_a)) \n",
    "print('通过类名调用类装饰器装饰了的静态方法')\n",
    "print(cls_b.static_fun(2,4))\n",
    "print('通过对象调用类装饰器装饰了的静态方法')\n",
    "print(obj_a.static_fun(2,4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "|-总结:\n",
    "     由上例可知当静态方法和类方法用装饰器装饰了之后,既可以通过类调用又可以通过对象调用\n",
    "    而且不可以在使用了方法装饰器之后的函数中使用self变量和函数\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<__main__.clas_a object at 0x00000197485FAC88> 1 2\n",
      "<__main__.clas_a object at 0x00000197485FA848> 1 2\n"
     ]
    }
   ],
   "source": [
    "class clas_a:\n",
    "    def __init__(self,a,b):\n",
    "        self.a = a\n",
    "        self.b = b\n",
    "        print(self,a,b) #输出self的值\n",
    "obj_a = clas_a(1,2)\n",
    "obj_b = clas_a(1,2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "|-再论self含义:\n",
    "    由上例可知obj_a与obj_b是两个不同的对象他们的self值是不同的因此再次说明self与对象是一一对应的\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 变量的访问权限设置\n",
    "- Python提供了一种约定（下划线）来限制对成员（成员变量，成员函数）的访问：\n",
    "    - `_xxx 不能用’from module import *’导入`\n",
    "    - `__xxx__ 系统定义名字`\n",
    "    - `__xxx 类中的私有变量名`、\n",
    "    - `这里仅仅演示__xxx私有变量的使用`\n",
    " \n",
    " |-私有变量仅仅只能够在类内部使用,即不能用类名使用也不能用对象名使用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3 4\n",
      "1\n",
      "3\n",
      "4\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'\\nprint(clas_a.__a)\\nprint(obj_a.__a)\\nprint(obj_a.__a)\\n'"
      ]
     },
     "execution_count": 81,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\n",
    "class clas_a:\n",
    "    a = 1\n",
    "    def __init__(self,a,b):\n",
    "        self.a = a           #如果类变量名与成员变量名冲突则成员变量覆盖类变量\n",
    "        self.b = b\n",
    "        print(self.a,self.b)\n",
    "obj_a = clas_a(3,4)\n",
    "print(clas_a.a)\n",
    "print(obj_a.a)\n",
    "print(obj_a.b)\n",
    "'''\n",
    "print(clas_a.__a)\n",
    "print(obj_a.__a)\n",
    "print(obj_a.__a)\n",
    "'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 95,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3 4\n"
     ]
    },
    {
     "ename": "AttributeError",
     "evalue": "'clas_a' object has no attribute '__c'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-95-77c1b860247e>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     16\u001b[0m \u001b[1;31m#print(obj_a.__a)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     17\u001b[0m \u001b[1;31m#print(obj_a.__b)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 18\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mobj_a\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__c\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m: 'clas_a' object has no attribute '__c'"
     ]
    }
   ],
   "source": [
    "class clas_a:\n",
    "    __c = 1\n",
    "    def __init__(self,a,b):\n",
    "        self.__a = a           #如果类变量名与成员变量名冲突则成员变量覆盖类变量\n",
    "        self.__b = b\n",
    "        print(self.__a,self.__b)\n",
    "    @classmethod\n",
    "    def __func_a(self,e,f):\n",
    "        return e+f\n",
    "obj_a = clas_a(3,4)\n",
    "'''\n",
    "#下面语句都是错误的私有变量和私有函数只能够在类内部使用\n",
    "#print(obj_a.__func_a(1,2))\n",
    "#print(clas_a.__func_a(1,2))\n",
    "#print(clas_a.__a)\n",
    "#print(obj_a.__a)\n",
    "#print(obj_a.__b)\n",
    "#print(obj_a.__c)\n",
    "'''"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "|-私有变量操作说明:\n",
    "    私有变量和方法只能够在类内部使用是不能够在类外部使用的,其目的是为了实现对象的封装性,确保数据不外漏.\n",
    "    要想对私有变量进行操作只能够利用方法,在类内部或者是对象内部的方法去进行操作,如下面的操作\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3 4\n",
      "输出初始值\n",
      "3 4 1\n",
      "输出修改后的私有变量值:\n",
      "7 8 1\n"
     ]
    }
   ],
   "source": [
    "class clas_a:\n",
    "    __c = 1\n",
    "    def __init__(self,a,b):\n",
    "        self.__a = a          \n",
    "        self.__b = b\n",
    "        print(self.__a,self.__b)\n",
    "    @classmethod\n",
    "    def __func_a(self,e,f):\n",
    "        return e+f\n",
    "    def get_func(self):\n",
    "        print(self.__a,self.__b,clas_a.__c) #获取private variable value也可以用return返回\n",
    "    def set_func(self,a,b,c):       #设置private variable value\n",
    "        self.__a = a\n",
    "        self.__b = b        \n",
    "        __c = c\n",
    "obj_a = clas_a(3,4)\n",
    "print('输出初始值')\n",
    "obj_a.get_func()\n",
    "obj_a.set_func(7,8,9)\n",
    "print('输出修改后的私有变量值:')\n",
    "obj_a.get_func()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
